#pragma once

#include "TypedProperty.h"
#include <boost/shared_ptr.hpp>

namespace My {

template <typename S, typename T>
class GetPropertySPtrValueFunction : 
	public ReadAccess<T>, 
	public PropertyAccess< boost::shared_ptr<S> > {
public:
	typedef boost::shared_ptr<S> SPtr;
public:
	GetPropertySPtrValueFunction(BasicProperty<SPtr> & owner, T (S::* ptr)() const)
		: PropertyAccess<SPtr>(owner), m_pGet(ptr) { }
public:
	virtual bool GetValue(const EditableObject & obj, T & value) const {
		if (m_pGet == 0)
			return false;
		SPtr tmp;
		if (!m_Owner.GetValue(obj, tmp) || !tmp)
			return false;
		value = ((*tmp).*m_pGet)();
		return true;
	}
protected:
	T (S::*	m_pGet)() const;
};

template <typename S, typename T>
class SetPropertySPtrValueFunction : 
	public WriteAccess<T>, 
	public PropertyAccess< boost::shared_ptr<S> > {
public:
	typedef boost::shared_ptr<S> SPtr;
public:
	SetPropertySPtrValueFunction(BasicProperty<SPtr> & owner, void (S::* ptr)(T))
		: PropertyAccess<SPtr>(owner), m_pSet(ptr) { }
public:
	virtual void SetValue(EditableObject & obj, const T & value) const {
		if (m_pSet == 0)
			return;
		SPtr tmp;
		if (!m_Owner.GetValue(obj, tmp) || !tmp)
			return;
		((*tmp).* m_pSet)(value);
	}
protected:
	void (S::*	m_pSet)(T);
};

template <typename T, typename S>
inline boost::shared_ptr< ReadAccess<T> > Read(BasicProperty< boost::shared_ptr<S> > & owner, T (S::* ptr)() const)
	{ return boost::shared_ptr< ReadAccess<T> >(new GetPropertySPtrValueFunction<S, T>(owner, ptr)); }

template <typename T, typename S>
inline boost::shared_ptr< WriteAccess<T> > Write(BasicProperty< boost::shared_ptr<S> > & owner, void (S::* ptr)(T))
	{ return boost::shared_ptr< WriteAccess<T> >(new SetPropertySPtrValueFunction<S, T>(owner, ptr)); }

template <typename S, typename T>
inline boost::shared_ptr< ReadWriteAccess<T> > ReadOnly(BasicProperty< boost::shared_ptr<S> > & owner, T (S::* ptr)() const)
	{ return boost::shared_ptr< ReadWriteAccess<T> >(new ReadWriteImpl<T>(Read(owner, ptr))); }

template <typename T>
inline boost::shared_ptr< ReadWriteAccess<T> > ReadOnly(boost::shared_ptr< ReadAccess<T> > pGet)
	{ return boost::shared_ptr< ReadWriteAccess<T> >(new ReadWriteImpl<T>(pGet)); }
 
} // My
